package cn.ultrarisk.scadmin.manager.biz.zookeeper.operator;

import org.apache.log4j.Logger;
import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * ZookeeperOperator
 *
 * @author sevendlong(lin23871@163.com)
 * @date 2014/5/10
 * @since V1.0
 */
@Component
public class ZookeeperOperator {
    private Logger log = Logger.getLogger(ZookeeperOperator.class);

    @Value("${zk.host}")
    private String host;
    @Value("${zk.sessionTimeout}")
    private Integer sessionTimeout;

    private ZooKeeper zooKeeper;

    @PostConstruct
    public void init() {
        connect();
    }

    @PreDestroy
    public void destory() {
        close();
    }

    public void connect() {
        if (this.zooKeeper == null) {
            synchronized (this) {
                if (this.zooKeeper == null) {
                    try {
                        this.zooKeeper = new ZooKeeper(host, sessionTimeout, new Watcher() {
                            @Override
                            public void process(WatchedEvent event) {
                            }
                        });
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    public void close() {
        if (this.zooKeeper != null) {
            synchronized (this) {
                if (this.zooKeeper != null) {
                    try {
                        this.zooKeeper.close();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    private String formatPath(String path) {
        return path.startsWith("/") ? path : ("/" + path);
    }

    public List<String> getChildren(String path) {
        try {
            List<String> childPaths = this.zooKeeper.getChildren(formatPath(path), false);
            List<String> formatChildPaths = new ArrayList<String>();
            for (String childPath : childPaths) {
                formatChildPaths.add(path.equals("/") ? formatPath(childPath) : (path + formatPath(childPath)));
            }
            return formatChildPaths;
        } catch (Exception e) {
            log.error(e.getMessage());
        }
        return null;
    }

    public String getData(String path, Stat stat) {
        try {
            if (stat == null) {
                stat = getStat(path);
            }
            byte[] data = this.zooKeeper.getData(formatPath(path), false, stat);
            if (data == null) {
                return null;
            }
            try {
                return new String(data, "UTF-8");
            } catch (Exception e) {
                return new String(data);
            }
        } catch (Exception e) {
            log.error(e.getMessage());
        }
        return null;
    }

    public void create(String path, String data) {
        try {
            if (getStat(path) == null) {
                this.zooKeeper.create(path, data.getBytes("utf-8"), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
            } else {
                putData(path, data);
            }
        } catch (Exception e) {
            log.error(e.getMessage());
        }
    }

    public void putData(String path, String data) {
        try {
            this.zooKeeper.setData(path, data.getBytes("UTF-8"), -1);
        } catch (Exception e) {
            log.error(e.getMessage());
        }
    }

    public void delete(String path) {
        try {
            this.zooKeeper.delete(path, -1);
        } catch (Exception e) {
            log.error(e.getMessage());
        }
    }

    public boolean hasChild(Stat stat) {
        return stat.getNumChildren() > 0;
    }

    public Stat getStat(String path) {
        try {
            return this.zooKeeper.exists(formatPath(path), false);
        } catch (Exception e) {
            log.error(e.getMessage());
        }
        return null;
    }
}
